#include <iostream>
#include <cstdlib>
#include <unistd.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

using namespace std;

void Usage(std::string proc)
{
    std::cout << "\n\rUsage: " << proc << " serverip serverport\n"
              << std::endl;
}

// ./udpclient serverip serverport

int main(int argc, const char *argv[])
{
    if (argc != 3)
    {
        Usage(argv[0]);
        exit(0);
    }

    string ip = argv[1];
    uint16_t port = (uint16_t)stoi(argv[2]);

    struct sockaddr_in serveraddr;  
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_addr.s_addr = inet_addr(ip.c_str());
    serveraddr.sin_port = htons(port);

    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd < 0)
    {
        cout << "create socket error" << endl;
        return -1;
    }
     // client 要bind吗？要！只不过不需要用户显示的bind！一般有OS自由随机选择！
    // 一个端口号只能被一个进程bind，对server是如此，对于client，也是如此！
    // 其实client的port是多少，其实不重要，只要能保证主机上的唯一性就可以！
    // 系统什么时候给我bind呢？首次发送数据的时候

    string msg;
    char buffer[1024];

    while (1)
    {
        cout << "Please Enter@ ";
        getline(cin ,msg);
        sendto(sockfd, msg.c_str(), msg.size(), 0, (const struct sockaddr*)&serveraddr, sizeof(serveraddr));

        cout << "sendto over" << endl;
        struct sockaddr_in tmp;
        socklen_t len = sizeof(tmp);

        ssize_t n = recvfrom(sockfd, buffer, sizeof(buffer), 0, (struct sockaddr*)&tmp, &len); //udp的数据报(数据传输模式)类型的数据需要用recvfrom读取，tcp的字节流可以用read读取
        
        if(n > 0)
        {
            buffer[n] = 0;
            cout << buffer << endl;
        }
    }

    close(sockfd);    

    return 0;
}